package cn.skyquant.quant4j.jforex.sdk.strategy;

import com.dukascopy.api.*;

import java.util.*;

public abstract class BaseStrategy extends AbstractStrategy implements IStrategy{

    @Configurable("账户最大总亏损%")
    public int minEquit = 20;
    @Configurable("首仓间隔x分钟")
    public int f_sleep_time = 3;
    @Configurable("止损平仓后暂停X小时")
    public int sl_sleep_time = 24;

    protected final List<BaseConfig> configList = new ArrayList<BaseConfig>();
    protected final Map<String, BaseConfig> configMap = new HashMap<>();
    final Set<Instrument> instrumentSet = new HashSet<>();

    protected abstract String getVersion();
    protected abstract void init(InitEntity initEntity);

    protected class InitEntity{
        public final List<BaseConfig> a = new ArrayList<>();
        public final Set<Instrument> b = new HashSet<>();
        private final List<String> reasonList = new ArrayList<>();
        public boolean r = false;

        private InitEntity() {
        }
        public void addReason(String reason){
            reasonList.add(reason);
        }
    }

    long begin;
    @Override
    public final void onStartEx(){
        begin = System.currentTimeMillis();
        mpm = new MethodProcessManager(mpm_limit,console.getOut());
        InitEntity initEntity = new InitEntity();
        init(initEntity);
        if (!initEntity.r) {
            initEntity.reasonList.forEach(x->{if(log_start_stop) err(x);});
            warn("[%s %s] must be quit!",getName(),getVersion());
            context.stop();
            return;
        }
        initEntity.a.stream().filter(x->x.isValid()).forEach(x->{
            configList.add(x);
            configMap.put(x.getKey(),x);
        });
        instrumentSet.addAll(initEntity.b);
        context.setSubscribedInstruments(instrumentSet);
    }

    @Override
    public void onStopEx(){
        if(log_start_stop) out("%s %s stop",getName(),getVersion());
        mpm.add("all",begin,System.currentTimeMillis());
        if(isTestMode()) mpm.print();
    }

    //修改订单止盈止损价
    protected void updateSLTP(List<OrderEx> orders, double sl, double tp) {
        if (orders == null || orders.isEmpty()) {
            return;
        }
        for (OrderEx orderEx : orders) {
            if(orderEx.order==null){
                continue;
            }
            IOrder order = orderEx.order;
            try {
                if (order.getStopLossPrice() != sl) {
                    order.setStopLossPrice(sl);
                }
                if (order.getTakeProfitPrice() != tp) {
                    order.setTakeProfitPrice(tp);
                }
            } catch (JFException e) {
                if(log_error) warn("update price error,order=%s,sl=%f,tp=%f,message=%s" ,orderEx , sl , tp,e.getMessage());
            }
        }
    }

    //平仓所有订单
    protected final void closeOrders(Collection<IOrder> orderList) {
        do {
            boolean canBreak = true;
            for (IOrder order:orderList){
                IOrder.State state = order.getState();
                if(state== IOrder.State.FILLED){
                    try {
                        order.close();
                        order.waitForUpdate(2000, IOrder.State.CLOSED);
                    } catch (JFException e) {

                    }
                    if(order.getState()==IOrder.State.CLOSED){
                        canBreak = false;
                    }
                }else if(state== IOrder.State.OPENED){
                    try {
                        order.close();
                        order.waitForUpdate(2000, IOrder.State.CANCELED);
                    } catch (JFException e) {
                        if(log_error) warn("closeOrder:%s ,error:%s",order.toString(),e.getMessage());
                    }
                    if(order.getState()==IOrder.State.CANCELED){

                    }else {
                        canBreak = false;
                    }
                }
            }
            if(canBreak){
                break;
            }
        }while (true);
    }

    //从指定时间到当前时间，找最低价
    protected double getLowPrice(Instrument instrument, long fromtime, Period p) {
        try {
            long from = history.getNextBarStart(p, fromtime);
            long to = history.getBarStart(p, context.getTime());
            if (from > to) {
                return 100000;
            }
            List<IBar> iBarList = history.getBars(instrument, p, OfferSide.ASK, Filter.WEEKENDS, from, to);//计算从开首仓到最后一仓这些日子的bar
            return iBarList.stream().mapToDouble(x -> x.getLow()).min().getAsDouble();
        } catch (JFException e) {
            err("getLowPrice error %s:", e.getMessage());
            return 100000;
        }
    }

    //从指定时间到当前时间，找最高价
    protected double getHighPrice(Instrument instrument, long fromtime, Period p) {
        try {
            long to = history.getBarStart(p, context.getTime());
            long from = history.getNextBarStart(p, fromtime);
            if (from > to) {
                return 0;
            }
            List<IBar> iBarList = history.getBars(instrument, p, OfferSide.ASK, Filter.WEEKENDS, from, to);//计算从开首仓到最后一仓这些日子的bar
            return iBarList.stream().mapToDouble(x -> x.getHigh()).max().getAsDouble();
        } catch (JFException e) {
            err("getHighPrice error %s:", e.getMessage());
            return 0;
        }
    }
}
